﻿using Base.Api.Models;
using Base.Api.Repository;
using Base.Data.Entity;
using Base.Data.Entity.Base;
using Common.AspNetCore;
using Common.Infrastructure;
using Common.Infrastructure.Structs;
using Common.Infrastructure.Utils;
using Common.Models.Base;
using Microsoft.Extensions.Configuration;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Base.Api.Service
{
    public class BaseService : CommonService
    {
        private readonly IConfiguration config;
        private readonly BaseRepository baseRepository;

        public BaseService(IServiceProvider provider, IConfiguration c, BaseRepository baseRep) : base(provider)
        {
            this.config = c;
            this.baseRepository = baseRep;
        }

        public async Task<bool> FullUpdateMemberAsync(m_member mmember)
        {
            var member = new t_member()
            {
                id = mmember.id,
                org_id = mmember.org_id,
                create_time = mmember.create_time,
                modify_time = mmember.modify_time,
                row_version = mmember.row_version,
                is_deleted = mmember.is_deleted,
                area_id = mmember.area_id,
                responsible_id = mmember.responsible_id,
                superior_lcp_code = mmember.superior_lcp_code,
                iqc_power_level = mmember.iqc_power_level,
            };
            LibSysUtils.CopyObject(member, mmember);

            List<t_member> addMembers = new List<t_member>();
            List<t_member> updateMembers = new List<t_member>();
            List<t_user> addUsers = new List<t_user>();
            List<t_user> updateUsers = new List<t_user>();
            if (string.IsNullOrEmpty(member.id))
            {
                this.SetEntityId(member);
                member.password = "e10adc3949ba59abbe56e057f20f883e";
                addMembers.Add(member);
            }
            else
            {
                var entity = await this.baseRepository.CommonRepository.GetEntityAsync<t_member>(member.id);
                if (entity == null)
                {
                    member.password = "e10adc3949ba59abbe56e057f20f883e";
                    addMembers.Add(member);
                }
                else
                {
                    updateMembers.Add(member);
                }
            }

            t_user user = null;
            var ucode = string.IsNullOrEmpty(mmember.user_code) ? member.code : mmember.user_code;
            if (!string.IsNullOrEmpty(ucode))
            {
                user = await this.baseRepository.CommonRepository.GetEntityAsync<t_user>(null, t => t.code == ucode);
            }

            if (user == null && !string.IsNullOrEmpty(member.user_id))
            {
                user = await this.baseRepository.CommonRepository.GetEntityAsync<t_user>(null, t => t.id == member.user_id);
            }

            if (user == null)
            {
                user = new t_user();
                this.SetEntityId(user, member.id);
                user.org_id = member.org_id;
                member.user_id = user.id;
                user.user_lcp_code = string.IsNullOrEmpty(mmember.user_lcp_code) ? member.code : mmember.user_lcp_code;
                addUsers.Add(user);
            }
            else
            {
                var members = await this.baseRepository.CommonRepository.GetEntitiesAsync<t_member>(p => p.user_id == user.id && p.org_id == member.org_id && p.id != member.id);
                if (members != null && members.Any())
                {
                    this.AddError("00100005", null);
                    return false;
                }

                member.user_id = user.id;
                updateUsers.Add(user);
                user.user_lcp_code = mmember.user_lcp_code;
            }

            user.code = string.IsNullOrEmpty(mmember.user_code) ? member.code : mmember.user_code;
            user.name = member.name;
            user.phone = member.phone;
            user.att_files = mmember.att_files;
            user.user_post_id = mmember.user_post_id;
            user.depart_id = mmember.depart_id;
            user.sex = mmember.sex;
            user.position_code = mmember.position_code;
            user.sequ_code = mmember.sequ_code;
            user.sequ_name = mmember.sequ_name;
            user.subsq_code = mmember.subsq_code;
            user.subsq_name = mmember.subsq_name;
            user.chapter_code = mmember.chapter_code;
            user.superior_lcp_code = mmember.superior_lcp_code;
            user.iqc_power_level = mmember.iqc_power_level;
            user.area_id = mmember.area_id;
            user.job_class = mmember.job_class;
            user.work_territory = mmember.work_territory;
            user.api_key = mmember.api_key;
            user.entry_date = mmember.entry_date;
            user.user_type = mmember.user_type;
            user.responsible_id = mmember.responsible_id;
            user.dir_indir_class = mmember.dir_indir_class;

            await this.baseRepository.CommitChangesByCommonAsync(() =>
            {
                this.baseRepository.CommonRepository.AddEntities(addMembers);
                this.baseRepository.CommonRepository.AddEntities(addUsers);
                this.baseRepository.CommonRepository.UpdateEntities(updateMembers);
                this.baseRepository.CommonRepository.UpdateEntities(updateUsers);
            });

            return true;
        }

        public async Task FullUpdateRoleAsync(t_role member)
        {
            List<t_role> addMembers = new List<t_role>();
            List<t_role> updateMembers = new List<t_role>();
            if (string.IsNullOrEmpty(member.id))
            {
                this.SetEntityId(member);
                addMembers.Add(member);
            }
            else
            {
                var entity = await this.baseRepository.CommonRepository.GetEntityAsync<t_role>(member.id);
                if (entity == null)
                {
                    addMembers.Add(member);
                }
                else
                {
                    updateMembers.Add(member);
                }
            }

            await this.baseRepository.CommitChangesByCommonAsync(() =>
            {
                this.baseRepository.CommonRepository.AddEntities(addMembers);
                this.baseRepository.CommonRepository.UpdateEntities(updateMembers);
            });
        }

        public async Task FullUpdateRoleGroupAsync(t_role_group member)
        {
            List<t_role_group> addMembers = new List<t_role_group>();
            List<t_role_group> updateMembers = new List<t_role_group>();
            if (string.IsNullOrEmpty(member.id))
            {
                this.SetEntityId(member);
                addMembers.Add(member);
            }
            else
            {
                var entity = await this.baseRepository.CommonRepository.GetEntityAsync<t_role_group>(member.id);
                if (entity == null)
                {
                    addMembers.Add(member);
                }
                else
                {
                    updateMembers.Add(member);
                }
            }

            await this.baseRepository.CommitChangesByCommonAsync(() =>
            {
                this.baseRepository.CommonRepository.AddEntities(addMembers);
                this.baseRepository.CommonRepository.UpdateEntities(updateMembers);
            });
        }

        public async Task<List<EnumInfo>> GetAllEnumsAsync(ApiParam apiParam)
        {
            var localhostEnums = LibEnumUtils.GetLibEnumInfos("Common.Enums*.dll");
            var isGetDisableEnum = LibSysUtils.ToBoolean(apiParam.Params.FirstOrDefault(t => t.Key == "is_get_disable_enum")?.Value);
            var storeEnums = await this.CallService.PostListAsync<EnumInfo>("FCP", "FCP/GetEnumInfos", apiParam);
            if (!storeEnums.Any())
            {
                return localhostEnums;
            }

            List<EnumInfo> ret = new List<EnumInfo>();
            ret.AddRange(localhostEnums);
            storeEnums.ForEach(t =>
            {
                var ts = ret.FirstOrDefault(t1 => t1.EnumName == t.EnumName);
                if (ts != null)
                {
                    var loc = ts;
                    ts.Options = t.Options;

                    if (isGetDisableEnum)
                    {
                        loc?.Options?.OrderBy(t2 => t2.SortIndex).ForEach(t4 =>
                        {
                            if (!t.Options.Any(t5 => t5.Value == t4.Value))
                            {
                                t.Options.Add(new EnumDetailInfo() { Label = t4.Label, SortIndex = t4.SortIndex, Value = t4.Value });
                            }
                        });
                    }
                }
                else
                {
                    ret.Add(t);
                }
            });
            return ret;
        }

        public async Task<List<EnumByStringInfo>> GetEnumByStringInfosByEnumNameAsync(ApiParam apiParam)
        {
            var storeEnums = await this.CallService.PostListAsync<EnumByStringInfo>("FCP", "FCP/GetEnumByStringInfosByEnumName", apiParam);
            return storeEnums;
        }

        public async Task InitMemberPwdAsync(ApiParam apiParam)
        {
            var ids = apiParam.Keyword.Split(',').ToList();
            var members = await this.baseRepository.CommonRepository.GetEntitiesAsync<t_member>(ids);
            members.ForEach(t =>
            {
                t.password = "e10adc3949ba59abbe56e057f20f883e";
            });

            await this.baseRepository.CommitChangesByCommonAsync(() =>
            {
                this.baseRepository.CommonRepository.UpdateEntities(members);
            });
        }

        public async Task ChangeMemberPwdAsync(MemberPwdChangeParamModel model)
        {
            LibCheckNullUtils.CheckNull(model, "model");
            LibCheckNullUtils.CheckNull(model.MemberId, "model.MemberId");
            LibCheckNullUtils.CheckNull(model.OldPwd, "model.OldPwd");
            LibCheckNullUtils.CheckNull(model.Pwd, "model.Pwd");
            var m = await this.baseRepository.CommonRepository.GetEntityAsync<t_member>(model.MemberId);
            if (m == null)
            {
                return;
            }

            if (string.Compare(m.password, model.OldPwd, true) != 0)
            {
                LibMessageUtils.AddError(this.Provider, "00100003", null);
                return;
            }

            m.password = model.Pwd;
            await this.baseRepository.CommitChangesByCommonAsync(() =>
            {
                this.baseRepository.CommonRepository.UpdateEntity(m);
            });
        }

        public async Task<bool> SaveBaseLabelByMenuAsync(MenuLabelParamModel model)
        {
            var lang = !string.IsNullOrEmpty(this.config["DefaultLang"]) ? this.config["DefaultLang"] : "CN";
            var menus = await this.baseRepository.CommonRepository.GetEntitiesAsync<t_menu>(model.MenuIds);

            var ids = menus.Where(t => !string.IsNullOrEmpty(t.label_base_label_id)).Select(t => t.label_base_label_id).ToList();

            List<t_menu> updateMenus = new List<t_menu>();
            List<t_base_label> addBaseLabels = new List<t_base_label>();

            List<t_base_label> updateBaseLabels = new List<t_base_label>();
            List<t_base_label_detail> addBaseLabelDetails = new List<t_base_label_detail>();
            List<t_base_label_detail> updateBaseLabelDetails = new List<t_base_label_detail>();

            var baseLabels = ids.Any() ? await this.baseRepository.CommonRepository.GetEntitiesAsync<t_base_label>(ids) : null;
            var baseLabelDetails = ids.Any() ? await this.baseRepository.CommonRepository.GetEntitiesAsync<t_base_label_detail>(this.baseRepository.CommonRepository.GetApiParamByIds(ids), t => ids.Contains(t.base_label_id)) : null;

            foreach (var menu in menus)
            {
                t_base_label baseLabel = baseLabels?.FirstOrDefault(t => t.id == menu.label_base_label_id);
                if (baseLabel == null)
                {
                    baseLabel = new t_base_label() { type = 1, org_id = menu.org_id, api_key = model.ApiKey };
                    this.SetEntityId(baseLabel);
                    addBaseLabels.Add(baseLabel);
                    menu.label_base_label_id = baseLabel.id;
                    updateMenus.Add(menu);
                }

                var detail = baseLabelDetails?.FirstOrDefault(t => t.base_label_id == baseLabel.id && t.lang == lang);
                if (detail == null)
                {
                    detail = new t_base_label_detail() { base_label_id = baseLabel.id, org_id = baseLabel.org_id, lang = lang };
                    this.SetEntityId(detail, detail.base_label_id);
                    addBaseLabelDetails.Add(detail);
                }
                else
                {
                    updateBaseLabelDetails.Add(detail);
                }

                detail.label = menu.label;
            }

            await this.baseRepository.CommitChangesByCommonAsync(() =>
            {
                this.baseRepository.CommonRepository.UpdateEntities(menus);
                this.baseRepository.CommonRepository.AddEntities(addBaseLabels);
                this.baseRepository.CommonRepository.AddEntities(addBaseLabelDetails);
                this.baseRepository.CommonRepository.UpdateEntities(updateBaseLabels);
                this.baseRepository.CommonRepository.UpdateEntities(updateBaseLabelDetails);
            });

            return !this.HasThrow;
        }

        public async Task<List<m_member>> GetMembersByIdsAsync(ModelIdRequest model)
        {
            List<m_member> ret = new List<m_member>();
            var ms = await this.baseRepository.CommonRepository.GetEntitiesAsync<t_member>(model.Ids);
            if (ms == null || !ms.Any())
            {
                return ret;
            }

            var mis = ms.Select(t => t.user_id).ToList();
            var us = await this.baseRepository.CommonRepository.GetEntitiesAsync<t_user>(mis);
            var param = new ApiParam();
            param.OrgId = ms.FirstOrDefault().org_id;
            var responsibleIds = us.Where(t => !string.IsNullOrEmpty(t.responsible_id)).Select(t => t.responsible_id).ToList();
            var responsibles = responsibleIds.Any() ? await this.baseRepository.CommonRepository.GetEntitiesAsync<t_user>(responsibleIds) : null;
            var tarea = await this.baseRepository.CommonRepository.GetEntitiesAsync<t_iqc_area>(p => p.org_id == param.OrgId);
            ///var area = await this.baseRepository.CommonModelRepository.GetOrderModelsAsync<m_iqc_area>(param);
            var pis = us.Where(t => !string.IsNullOrEmpty(t.user_post_id)).Select(t => t.user_post_id).ToList();
            var pps = pis.Any() ? await this.baseRepository.CommonRepository.GetEntitiesAsync<t_user_post>(pis) : null;
            var departIds = us.Where(t => !string.IsNullOrEmpty(t.depart_id)).Select(t => t.depart_id).ToList();
            var departs = pis.Any() ? await this.baseRepository.CommonRepository.GetEntitiesAsync<t_department>(departIds) : null;

            ms.ForEach(t =>
            {
                var pp = new m_member()
                {
                    id = t.id,
                    org_id = t.org_id,
                    create_time = t.create_time,
                    modify_time = t.modify_time,
                    row_version = t.row_version,
                    is_deleted = t.is_deleted
                };
                LibSysUtils.CopyObject(pp, t);
                var u = us.FirstOrDefault(t1 => t1.id == t.user_id);
                if (u != null)
                {
                    pp.user_post_id = u.user_post_id;
                    pp.att_files = u.att_files;
                    pp.phone = u.phone;
                    pp.user_code = u.code;
                    pp.user_lcp_code = u.user_lcp_code;
                    pp.sex = u.sex;
                    pp.position_code = u.position_code;
                    pp.sequ_code = u.sequ_code;
                    pp.sequ_name = u.sequ_name;
                    pp.subsq_code = u.subsq_code;
                    pp.chapter_code = u.chapter_code;
                    pp.superior_lcp_code = u.superior_lcp_code;
                    pp.area_id = u.area_id;
                    pp.iqc_power_level = u.iqc_power_level;
                    pp.subsq_name = u.subsq_name;
                    pp.job_class = u.job_class;
                    pp.work_territory = u.work_territory;
                    pp.dir_indir_class = u.dir_indir_class;
                    pp.entry_date = u.entry_date;
                    pp.user_type = u.user_type;
                    pp.responsible_id = u.responsible_id;
                    var responsible = responsibles?.FirstOrDefault(p => p.id == u.responsible_id);
                    if (responsible != null)
                    {
                        var responsiblem = new m_user()
                        {
                            id = responsible.id,
                            org_id = responsible.org_id,
                            create_time = responsible.create_time,
                            modify_time = responsible.modify_time,
                            row_version = responsible.row_version,
                            is_deleted = responsible.is_deleted
                        };
                        LibSysUtils.CopyObject(responsiblem, responsible);
                        pp.nav_responsibleUser = responsiblem;
                    }

                    var area = tarea?.FirstOrDefault(p => p.id == u.area_id);
                    if (area != null)
                    {
                        var aream = new m_iqc_area()
                        {
                            id = area.id,
                            org_id = area.org_id,
                            create_time = area.create_time,
                            modify_time = area.modify_time,
                            row_version = area.row_version,
                            is_deleted = area.is_deleted
                        };
                        LibSysUtils.CopyObject(aream, area);
                        pp.nav_iqcArea = aream;
                    }

                    var userP = pps?.FirstOrDefault(t1 => t1.id == u.user_post_id);
                    if (userP != null)
                    {
                        var upm = new m_user_post()
                        {
                            id = userP.id,
                            org_id = userP.org_id,
                            create_time = userP.create_time,
                            modify_time = userP.modify_time,
                            row_version = userP.row_version,
                            is_deleted = userP.is_deleted
                        };
                        LibSysUtils.CopyObject(upm, userP);
                        pp.nav_userPost = upm;
                    }

                    var userDepart = departs?.FirstOrDefault(t1 => t1.id == u.depart_id);
                    if (userDepart != null)
                    {
                        var mdepart = new m_department()
                        {
                            id = userDepart.id,
                            org_id = userDepart.org_id,
                            create_time = userDepart.create_time,
                            modify_time = userDepart.modify_time,
                            row_version = userDepart.row_version,
                            is_deleted = userDepart.is_deleted,
                            parent_id = userDepart.parent_id,
                        };
                        LibSysUtils.CopyObject(mdepart, userDepart);
                        pp.nav_depart = mdepart;
                    }
                }

                ret.Add(pp);
            });
            return ret;
        }
    }
}
